/*
 * Copyright (c) 2007 Compl Yue Still, All Rights Reserved.
 */

/**
 * 
 */
package hbi.wire.java.host;

import hbi.task.TaskAgent;
import hbi.task.java.AgentMethodInvocation;
import hbi.task.java.TaskAgentLifeScript;
import hbi.wire.ProtocolError;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.nio.ByteBuffer;
import java.util.LinkedList;

public class TaskScript implements IncomingTag
{

    final HostEnd hostEnd;

    public TaskScript(HostEnd hostEnd)
    {
        this.hostEnd = hostEnd;
    }

    ResolvedType agentType = null;

    final LinkedList<Annotation> headers = //
    new LinkedList<Annotation>();

    final LinkedList<AgentMethodInvocation> invocations = //
    new LinkedList<AgentMethodInvocation>();

    private IncomingTag incomingTag = null;

    public boolean processIncomingData(ByteBuffer buffer) throws IOException
    {
        tag_scan: while (buffer.hasRemaining())
        {
            if (incomingTag == null)
            {
                if (agentType == null)
                // type not ready yet
                {
                    if (buffer.remaining() < 4) return false;
                    int index = buffer.getInt();
                    if (index < 0)
                        throw new SecurityException("Too big index.");
                    ResolvedType agentType = hostEnd.getResolvedType(index);
                    if (!TaskAgent.class.isAssignableFrom(agentType.javaClass))
                        throw new ProtocolError("Not a Task Agent type.");
                    this.agentType = agentType;
                    if (!buffer.hasRemaining()) break tag_scan;
                }
                int tag = buffer.get() & 0xFF;
                switch (tag)
                {
                case 'c': // scripted method invocation
                    incomingTag = new MethodInvocation(this);
                    break;
                case 'm': // method constant
                    incomingTag = new MethodConstant(this.agentType);
                    break;
                case 'H': // meta header
                    incomingTag = new MetaHeader(this);
                    break;
                case 'z': // end of life script
                    hostEnd.hostTaskAgent(new TaskAgentLifeScript(
                        agentType.javaClass, headers, invocations));
                    return true;
                default:
                    throw new ProtocolError("Bad agent tag: " + tag);
                }
            }
            if (incomingTag.processIncomingData(buffer))
                incomingTag = null;
            else
                break tag_scan;
        }

        return false;
    }

}
